package auth

import (
	. "apiExample/common"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
	"time"
)

var (
	accessToken = ""
	mLock = &sync.Mutex{} //简单的锁即可，大部分只是读取一下
)
/*
	常驻进程，做token缓存
*/
func GetAccessToken() (string, error) {
	mLock.Lock()
	defer mLock.Unlock()
	var err error
	if accessToken != "" {
		return accessToken, nil
	} else {
		accessToken, err = GetAccessTokenOnce()
		if err == nil && accessToken != "" { //获取成功一次后，才开始定时更新
			go func(){
				for {
					time.Sleep(time.Second * (TokenExpire / 2)) //一半的过期时间更新一次，可以自行调整
					tmpAccessToken, err := GetAccessTokenOnce()
					if err == nil && tmpAccessToken != "" {
						mLock.Lock()
						accessToken = tmpAccessToken
						mLock.Unlock()
					}
				}
			}()
		}
		return accessToken, err
	}
}

type AccessToken struct {
	Result int32 `json:"result"`
	Errmsg string `json:"errmsg"`
	AccessToken string `json:"access_token"`
}

/*
	2.获取访问凭证
	工具程序，单次调用的时候不用做token管理
*/
func GetAccessTokenOnce() (string, error) {
	//获取完整的列表
	fullUrl := fmt.Sprintf("%s/cgi-bin/oauth/access_token?appid=%d&did=%d&secret=%s&expire=%d", ApiUrl, AppId, Did, AppSecret, TokenExpire)

	rsp, err := http.Get(fullUrl)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Get access token from server, http error = %v", err))
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != 200 {
		return "", errors.New(fmt.Sprintf("Get acess token from server, http response status not 200, StatusCode=%v", rsp.StatusCode))
	}

	rspBody, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Get acess token from server, read http rsp body failed! err=%v", err))
	}

	token := &AccessToken{}
	err = json.Unmarshal(rspBody, token)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Get acess token from server, umarshal body failed! err=%v", err))
	}

	if token.Result != 0 {
		return "", errors.New(fmt.Sprintf("Get acess token from server, server respone not ok, result=%v,msg=%s", token.Result, token.Errmsg))
	}

	if token.AccessToken == "" {
		return "", errors.New(fmt.Sprintf("Get acess token from server, server not respone access_token!! rsp body=%s", string(rspBody)))
	}

	return token.AccessToken, nil
}
